#include<stdio.h>
void printyhsj(int n) {
	int arr[30][30] = { 1 };
	//行
	for (int i = 0; i < n; ++i) {
		//列
		for (int j = 0; j <= i; ++j) {
			if (j == 0 || i == j) {
				arr[i][j] = 1;
			}
			else {
				arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
			}
		}
	}

	//print
	for (int i = 0; i < n; ++i) {
		//列
		for (int j = 0; j <= i; ++j) {
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	//1
	//1 1
	//1 2 1
	//1 3 3 1
}
//日本某地发生了一件谋杀案，警察通过排查确定杀人凶手必为4个嫌疑犯的一个。

//以下为4个嫌疑犯的供词:
//A说：不是我。
//B说：是C。
//C说：是D。
//D说：C在胡说
//已知3个人说了真话，1个人说的是假话。
//现在请根据这些信息，写一个程序来确定到底谁是凶手。

void GuessC() {
	int ker = 0;
	for (ker = "a"; ker <= 'd'; ker++) {
		//3个人说了真话，1个人说的是假话 也就是四个表达式相加等于3
		if (((ker != 'a') + (ker == 'c') + (ker == 'd') + (ker != 'd')) == 3) {
			printf("%c \n", ker);
		}
	}
}

//5位运动员参加了10米台跳水比赛，有人让他们预测比赛结果：
//A选手说：B第二，我第三；
//B选手说：我第二，E第四；
//C选手说：我第一，D第二；
//D选手说：C最后，我第三；
//E选手说：我第四，A第一；
//比赛结束后，每位选手都说对了一半，请编程确定比赛的名次。


void GuessN() {
	int arr[5];
	for (int a = 1; a < 6; ++a) {
		for (int b = 1; b < 6; ++b) {
			for (int c = 1; c < 6; ++c) {
				for (int d = 1; d < 6; ++d) {
					for (int e = 1; e < 6; ++e) {
						if(	(b == 2) + (a == 3) == 1
						&&	(b == 2) + (e == 4) == 1
						&&  (c == 1) + (d == 2) == 1
						&&  (c == 5) + (d == 3) == 1
						&&  (e == 4) + (a == 1) == 1){
							printf("a = %d , b = %d , c = %d, d = %d, e = %d \n", a, b, c, d, e);
						}
					}
				}
			}
		}
	}
}





//int main(){
//	char a[1000] = { 0 };
//	int i = 0;
//	for (i = 0; i < 1000; i++){
//		//存到第一个零的位置 就是计算的数组的长度 也就是255
//		//-1 -2 -3 ..... -128 127 126 125 124 ... 3 2 1 0
//		//-1 -2 -3 ..... -128 127 126 125 124 ... 3 2 1 0
//		a[i] = -1 - i;
//	}
//	printf("%d", strlen(a));
//	return 0;
//}


void check_sys()
{
	int i = 1;
	//低位存在低地址处 1就在低地址处存
	if ((*(char*)&i) == 1){
		printf("小端\n");
	}
	//低位存在高地址处 1就在高地址处存，&1 就会取到0
	else {
		printf("大端\n");
	}
}



//#include <stdio.h>
//int main(){
//
//	char a = -1;
//	//默认有符号char
//	//y 10000000 00000000 00000000 00000001
//	//f 11111111 11111111 11111111 11111110
//	//b 11111111 11111111 11111111 11111111
//	//存入 char 发生截断
//		11111111
//	//以%d 打印 发生整形提升 补符号位 (有符号数发生整形提升 高位补符号位)
//	//b 11111111 11111111 11111111 11111111
//	//f 11111111 11111111 11111111 11111110
//	//y 10000000 00000000 00000000 00000001 (最终打印结果 以十进制有符号整形打印)
//
//	signed char b = -1;
//	// 和第一个一样 都是有符号char
//
//	
//	unsigned char c = -1;
//
//	//无符号char
//	//y 10000000 00000000 00000000 00000001
//	//f 11111111 11111111 11111111 11111110
//	//b 11111111 11111111 11111111 11111111
//	//存入 char 发生截断
//		11111111
//	//以%d 打印 发生整形提升 补0 (无符号数发生整形提升 高位补0)
//	//b 00000000 00000000 00000000 11111111
//	//f 00000000 00000000 00000000 11111111
//	//y 00000000 00000000 00000000 11111111 (最终打印结果 以十进制无符号整形打印)
//
//	//最终输出为 -1 -1 255
//	printf("a=%d,b=%d,c=%d", a, b, c);
//	return 0;
//}
//


//#include <stdio.h>
//int main(){
//	char a = -128;
//	//vs下 char有符号
//	// y 10000000 00000000 00000000 10000000
//	// f 11111111 11111111 11111111 01111111
//	// b 11111111 11111111 11111111 10000000
//
//	//存入char 发生截断
//	 
//	//	 10000000
//
//	//以10进制无符号数打印 发生整形提升
//
//	// b 11111111 11111111 11111111 10000000 (有符号数发生整形提升 高位补符号位)
//	// 因为打印的是以无符号数形式打印 所以可以看做打印正数 原反补一样
//	// f 11111111 11111111 11111111 10000000
//	// y 11111111 11111111 11111111 10000000 打印4294967168
//	printf("%u\n", a);
//	return 0;
//}

//#include <stdio.h>
//int main()
//{
//	char a = 128;
//	// vs下看作有符号char
//	// y 00000000 00000000 00000000 10000000
//	// f 01111111 11111111 11111111 01111111
//	// b 01111111 11111111 11111111 10000000
//	// 存入char 发生截断
//	// b 10000000
//	//以10进制无符号数打印 发生整形提升
//	// b 11111111 11111111 11111111 10000000(有符号数发生整形提升 高位补符号位)
//	// 因为打印的是以无符号数形式打印 所以可以看做打印正数 原反补一样
//	// f 11111111 11111111 11111111 10000000
//	// b 11111111 11111111 11111111 10000000 打印4294967168
//	printf("%u\n", a);
//	return 0;
//}

//int main() {
//	//printyhsj(5);
//	//GuessC();
//	//GuessN();
//	//check_sys();
//	return 0;
//}

//int main() {
//	int i = -20;
//	//有符号int
//	// y 10000000 00000000 00000000 00010100
//	// f 11111111 11111111 11111111 11101011
//	// b 11111111 11111111 11111111 11101100
//	unsigned  int  j = 10;
//	//无符号int
//	// yfb 相同
//	// y 00000000 00000000 00000000 00001010
//
//	// i + j (补码相加)
//	// 11111111 11111111 11111111 11101100
//	//+00000000 00000000 00000000 00001010
//	//=11111111 11111111 11111111 11110110
//
//	//以有符号整形形式打印
//
//	// b 11111111 11111111 11111111 11110110
//	// f 10000000 00000000 00000000 00001001
//	// y 10000000 00000000 00000000 00001010 打印-10
//	printf("%d\n", i + j);
//	//按照补码的形式进行运算，最后格式化成为有符号整数
//	return 0;
//}


//int main() {
//	unsigned int i;
//	//无符号整形以十进制无符号整形打印
//	//正数部分按原来打印
//	//当i == 0 时
//	// i-- i变为-1
//	// y 10000000 00000000 00000000 00000001
//	// f 11111111 11111111 11111111 11111110
//	// b 11111111 11111111 11111111 11111111
//
//	// 因为无符号整形以%u打印 默认都是打印正数 正数原反补相同 就变为直接打印-1的补码
//	// 4294967295
//	// 而且i是一个无符号整数 没有符号位 所以i的值恒大于0 所以for循环一直运行 打印递减数
//	//	4294967295 4294967294 4294967293 ...... 3 2 1 0 4294967295 ......
//
//	for (i = 9; i >= 0; i--){
//		printf("%u\n", i);
//	}
//	return 0;
//}
//

#include <stdio.h>
unsigned char i = 0;
// yfb 00000000
// 当i==255 时
// i yfb 11111111
// 此时 i++再次进入循环
// i yfb 变为100000000
// 存入 unsigned char 发生截断
// 变为 yfb 00000000
// for循环成为死循环

//int main() {
//	for (i = 0; i <= 255; i++) {
//		printf("hello world\n");
//	}
//	return 0;
//}

//
//int main(){
//	int a[5] = { 1, 2, 3, 4, 5 };
//	//&a代表整个数组地址 +1 指向整个数组最后一个元素的下一个元素的地址
//	//转为int* 此时指针加1就变为了+类型也就是+int大小
//	int* ptr = (int*)(&a + 1);
//	//a直接出现 代表数组首元素地址 + 1 代表第二个元素地址 解引用 代表打印第二个元素
//	//ptr-1 ptr类型为int* -1 就是减到了a[5]位置的地址 解引用 代表打印第五个元素
//	printf("%d,%d", *(a + 1), *(ptr - 1));
//	return 0;
//}


////由于还没学习结构体，这里告知结构体的大小是20个字节
//struct Test {
//	int Num;
//	char* pcName;
//	short sDate;
//	char cha[2];
//	short sBa[4];
//}*p;
////假设p 的值为0x100000。 如下表表达式的值分别为多少？
//int main() {
//	//假设p为0x100000 那么p + 1 就是加整个结构体的大小 0x100000 + 20字节 20字节转换为16进制 14
//	// 第一个结果为0x100014
//	printf("%p\n", p + 0x1);
//	//强转为unsigned long后 p成为整数 整数+1 就是加1 
//	// 第二个结果为0x100001
//	printf("%p\n", (unsigned long)p + 0x1);
//	//强转为unsigned int*后 p+1 变为+int*大小字节 也就是4(x86环境下)
//	// 第三个结果为0x100004
//	printf("%p\n", (unsigned int*)p + 0x1);
//	return 0;
//}


//int main(){
//	int a[4] = { 1, 2, 3, 4 };
//	//&a 代表整个数组地址 + 1 加到整个数组最后一个元素的下一个元素位置
//	//强转为int* ++ 和 -- 变为+int类型大小
//	//ptr[-1] 就是访问 *(ptr - 1) 位置元素 由于当前ptr指向数组最后一个元素的下一个元素位置
//	//-1也就是减去类型大小int 就到了数组最后一个元素位置 解引用 就是以16进制打印数组最后一个元素
//	//0x4
//	int* ptr1 = (int*)(&a + 1);
//
//	//a单独出现 代表数组首元素地址 也就是&a[0] 强转为int 再加一 说明给ptr2的指针加1个字节
//	//a数组在内存中的存储本来为
//	//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 (小端存储)
//	//此时地址加一个字节 ptr2指向了下一个字节
//	//此时ptr指向的内容在内存中的存储为
//	//00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ??
//	//此时再对ptr2解引用 ptr类型为int* 解引用访问一个int类型 
//	//此时访问的数据为 00 00 00 02(小端存储)
//	//用16进制打印为
//	// 02000000
//	int* ptr2 = (int*)((int)a + 1);
//	printf("%x,%x", ptr1[-1], *ptr2);
//	return 0;
//}


//#include <stdio.h>
//int main(){
//	//逗号表达式 实际的a=数组为
//	//a[3][2] = {1,3,5,0,0,0};
//	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
//	int* p;
//	//a[0] 数组的第一个元素赋值给 int*的指针
//	p = a[0];
//	// p[0] 就是 *(p+0)
//	//也就是访问a[0] 的第一个元素
//	printf("%d", p[0]);
//	//打印1
//	return 0;
//}


//int main(){
//	int a[5][5];
//	int(*p)[4];
//	p = a;
//	//int(*p)[4] 可以看做是一个p[][4] 的二维数组
//	// 地址-地址 得到的是两个地址之间的元素个数 小地址-大地址 得到 -元素个数
//	//以d% 打印 为-4
//	//以p% 打印 直接打印内存中的数据 -4以补码形式存储
//	//y 10000000 00000000 00000000 00000100
//	//f 11111111 11111111 11111111 11111011
//	//b 11111111 11111111 11111111 11111100
//	//然后以十六进制打印 FFFFFFFC
//	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
//	return 0;
//}

//int main(){
//	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//	// &aa 整个数组地址 + 1 数组最后一个元素的后一个元素的地址
//	// 转为int* ++ -- 变为+- int大小
//	// ptr1 - 1 数组最后一个元素的后一个元素的地址 - 一个int大小 也就是数组最后一个元素的最后一个元素的大小
//	// 得到数组最后一个元素的最后一个元素地址 解引用 打印数组最后一个元素的最后一个元素
//	// 10
//	int* ptr1 = (int*)(&aa + 1);
//	//aa 数组首元素地址 + 1 数组第二个元素地址 也就是&aa[1]
//	//转为int* ++ -- 变为+- int大小
//	// ptr2 - 1 数组第二个元素的前一个int大小地址 也就是数组第一个元素的最后一个元素地址
//	//解引用 打印数组第一个元素的最后一个元素
//	// 5
//	int* ptr2 = (int*)(*(aa + 1));
//	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
//	return 0;
//}

//#include <stdio.h>
//int main(){
//	char* a[] = { "work","at","alibaba" };
//	char** pa = a;
//	//pa++ pa指向元素位置+1 // 指向at
//	pa++;
//	printf("%s\n", *pa);
//	return 0;
//}

//int main(){
//	char* c[] = { "ENTER","NEW","POINT","FIRST" };
//	char** cp[] = { c + 3,c + 2,c + 1,c };
//	char*** cpp = cp;
//
//	printf("%s\n", **++cpp);
//	// ++cpp cpp指向元素向后指向一个元素
//	// cpp指向cp第二个元素 解引用 *(cpp + 1)
//	// 得到c的第三个元素 解引用*(c + 2)
//	// 打印 POINT
//
//	printf("%s\n", *-- * ++cpp + 3);
//	// ++cpp cpp指向元素向后指向一个元素
//	// cpp指向cp第三个元素 解引用 *(cpp + 1)
//	// 得到c的第三个元素 --cp指向第一个元素的地址
//	// 解引用得到c第一个元素地址 + 3 
//	// 从E开始往后打印 碰到 \0 结束
//
//	printf("%s\n", *cpp[-2] + 3);
//	//cpp[-2] == *(cpp - 2) 
//	//cpp指向cp的第一个元素 解引用 *cpp
//	//得到cp的第四个元素地址 解引用*(c + 3)
//	//得到c第四个元素地址 +3 
//	//得到c[3]指向数组的 第三个元素的地址
//	//从S开始往后打印 碰到 \0 结束
//	printf("%s\n", cpp[-1][-1] + 1);
//
//	// cpp[-1][-1] == *(*(cpp - 1) - 1)
//	// 访问cpp[-1] cpp指向数组的第二个元素 取得c+2
//	//*(c + 2 - 1) 得到c数组的第二个元素对其解引用
//	//得到c第二个元素指向的数组 + 1 
//	//从E开始往后打印 碰到 \0 结束
//	return 0;
//}

//size_t my_strlen(const char* str) {
//	int count = 0;
//	while (*str) {
//		count++;
//		str++;
//	}
//	return count;
//}

size_t my_strlen(const char* str) {
	if (*str == '\0')
		return 0;
	return my_strlen(str + 1) + 1;
}

#include<assert.h>

	char* my_strcpy(char* dst, const char* src) {
		assert(dst != NULL);
		assert(src != NULL);
		char* ret = dst;
		while (*src) {
			*dst = *src;
			src++;
			dst++;
		}
		*dst = *src;

		return dst;
	}

char* my_strcat(char* dst, const char* src) {
	assert(src);
	assert(dst);

	char* ret = dst;
	//找\0位置
	while (*dst) {
		++dst;
	}
	//追加拷贝
	while (*src) {
		*dst = *src;
		dst++;
		src++;
	}
	//源字符串末尾有\0 所以不用再次拷贝
	return ret;
}


int my_strcmp(const char* str1, const char* str2) {
	assert(str1 && str2);
	while (*str1 == *str2) {
		if (*str1 == '\0') {
			return 0;
		}
		str1++;
		str2++;
	}

	return (*str1 - *str2);
}

void* my_memcpy(void* dst, const void* src, size_t num) {
	//num单位是字节
	//强制类型转换是临时的
	assert(dst && src);
	char* ret = dst;
	while (num--) {
		*(char*)dst = *(char*)src;
		((char*)dst)++;
		((char*)src)++;
	}

	return ret;
}

void* my_memmove(void* dst, const void* src, size_t num) {
	//num单位是字节
	//强制类型转换是临时的
	assert(dst && src);

	char* ret = dst;
	if (dst > src) {
		// 后 -> 前
		while (num--) {
			//num进入循环 已经减一次了
			*((char*)dst + num) = *((char*)src + num);
		}
	}
	else {
		// 前 -> 后
		while (num--) {
			*(char*)dst = *(char*)src;
			((char*)dst)++;
			((char*)src)++;
		}
	}

	return ret;
}

char* my_strstr(char* str1, char* str2) {
	char* cp = str1;
	char* s1 = str1;
	char* s2 = str2;

	while (*cp) {
		s1 = cp;
		s2 = str2;
		while ((*s1) && (*s2) && (*s1 == *s2)) {
			s1++;
			s2++;
		}

		if (*s2 == '\0') {
			return cp;
		}

		cp++;
	}
	return NULL;
}
int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	int size = sizeof(arr1);
	my_memmove(arr1, arr1 + 2, 20);
	for (int i = 0; i < 10; ++i) {
		printf("%d ", arr1[i]);
	}


	//my_strcpy(arr2, arr1);
	//my_strncpy(arr2, arr1,3);
	//printf("%s\n", arr2);
	//printf("%d\n", my_strlen(str));
	return 0;
}